2015-05-22

Managing LXC hosts with ansible and a jump host

I wanted to be able to create a LXC guests using ansible and then manage said guests without having them public.

Since my last attempt two years ago things have changed

1 Create an LXC guest using ansible

this ended up beeing quite easy with the help of the lxc_container module.

It just needs the lxc package and python2-lxc.

1.1 python2-lxc and ubuntu 14.04

Sadly python2-lxc is not packaged for ubuntu 14.04, luckily pip made it easy to install

- apt: name={{item}}
  with_items:
    - python-pip
    - git
    - build-essential
    - python-dev
    - lxc-dev
pip: name=git+https://github.com/lxc/python2-lxc.git#egg=python2-lxc

1.2 Create the container !

Pretty easy, the documentation has a bunch of examples. I added the `container_command` so python would be installed before beeing contacted by ansible.

We could also configure the authorized_keys in there too.

- name: Prepare lxc-www1 container
  lxc_container:
    name: lxc-www1
    state: started
    template_options: --release trusty
    container_config:
      - "lxc.network.type=veth"
      - "lxc.aa_profile=unconfined"
    container_command: |
      apt-get install -y python
  register: www1_conf

The lxc_container's name can't be changed without popping a new container, also chose wisely … it will be repeated and reused as the playbook hostname and in ssh_config.

Now what's next ? How will the next play know this host has been created ?

2 add_host !

Using add_host we can declare a new host in memory

I couldn't make ansible use the ssh_args option so I couldn't dynamically add `-o ProxyCommand` for ansible to use.

- add_host: hostname=lxc-www1

And then, how do ansible connect to this unroutable guest ?!

3 The ssh connection

3.1 The Play

We reuse the name we used for the container name, in our example `lxc-www1`.

- hosts: lxc-www1
  tasks:
    - debug: var="hostvars['lxc-www1']"

3.2 The trick

Using a jump host is not new, we configure a ProxyCommand in our ~/.ssh/config that will forward our ssh connection to another host.

The issue, was how to connect to an LXC host we don't have the IP. Actually we have the IP by default it's in the 10.0.3.0/24. But since I also have LXC guests on my laptop, I didn't want to catch those ssh connections by setting `Host 10.0.3.*`. Instead I chose `lxc-*`.

Next, was how to forward the connection to the lxc guest, since I still don't have it's IP and the hostname doesn't resolve ?

lxc-attach can attach and run commands on the host, using `nc` we can now forward what the ssh client is sending to the ssh server on the guest.

Host my-lxc-host
Hostname X.X.X.X

Host lxc-*
ProxyCommand ssh my-lxc-host lxc-attach -n %h nc localhost 22

%h will use the hostname we are trying to contact, which is actually our lxc container name

4 Even better

It might be possible to tell ansible to use another ssh_config and keep everything along the rest of the configurations/playbooks.

If `add_host` could configure `ssh_args` it would be a simple matter of doing something like

- add_host:
    name=blahblah
    ssh_args="-o ProxyCommand ssh {{inventory_name}} -W {{www1_conf.lxc_container.ipv4[0]}}"